// Copyright (C) 2010  Joan Puigcerver Perez, <joapuipe@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#ifndef __GENRES_HPP__
#define __GENRES_HPP__

#include <iostream>

#include <BasicTypes.hpp>

/**
 * \class Genres
 *
 * Class that represents a set of genres.
 * Internally each genre type is represented as a bit in a 32-bit integer, so it is
 * easy and efficient to check is any specific genre is in the set performing a bitwise AND
 * operation.
 *
 */
class Genres {
private:  
  uint32_t _genres;
  
public:
  /** Action code */
  static const uint32_t ID_ACTION;
  /** Adult code */
  static const uint32_t ID_ADULT;
  /** Adventure code */
  static const uint32_t ID_ADVENT;
  /** Animation code */
  static const uint32_t ID_ANIMAT;
  /** Biography code */
  static const uint32_t ID_BIOGRA;
  /** Comedy code */
  static const uint32_t ID_COMEDY;
  /** Crime code */
  static const uint32_t ID_CRIME;
  /** Documentary code */
  static const uint32_t ID_DOCUMEN;
  /** Drama code */
  static const uint32_t ID_DRAMA;
  /** Family code */
  static const uint32_t ID_FAMILY;
  /** Fantasy code */
  static const uint32_t ID_FANTASY;
  /** Film-Noir code */
  static const uint32_t ID_FNOIR;
  /** Game-Show code */
  static const uint32_t ID_GSHOW;
  /** History code */
  static const uint32_t ID_HISTORY;
  /** Horror code */
  static const uint32_t ID_HORROR;
  /** Music code */
  static const uint32_t ID_MUSIC;
  /** Musical code */
  static const uint32_t ID_MUSICAL;
  /** Mystery code */
  static const uint32_t ID_MYSTERY;
  /** News code */
  static const uint32_t ID_NEWS;
  /** Reality-TV code */
  static const uint32_t ID_REALTV;
  /** Romance code */
  static const uint32_t ID_ROMANCE;
  /** Science-Fiction code */
  static const uint32_t ID_SCIFI;
  /** Short film code */
  static const uint32_t ID_SHORT;
  /** Sport code */
  static const uint32_t ID_SPORT;
  /** Talk-Show code */
  static const uint32_t ID_TSHOW;
  /** Thriller code */
  static const uint32_t ID_THRILL;
  /** War code */
  static const uint32_t ID_WAR;
  /** Western code */
  static const uint32_t ID_WESTERN;
  /** Unknown genre code */
  static const uint32_t ID_UNKNOWN;
  /** Wildcard very useful for filtering. */
  static const uint32_t ID_ALL;

  /** Action string representation. */
  static const char * TAG_ACTION;
  /** Adult string representation. */
  static const char * TAG_ADULT;
  /** Adventure string representation. */
  static const char * TAG_ADVENT;
  /** Animation string representation. */
  static const char * TAG_ANIMAT;
  /** Biography string representation. */
  static const char * TAG_BIOGRA;
  /** Comedy string representation. */
  static const char * TAG_COMEDY;
  /** Crime string representation. */
  static const char * TAG_CRIME;
  /** Documentary string representation. */
  static const char * TAG_DOCUMEN;
  /** Drama string representation. */
  static const char * TAG_DRAMA;
  /** Family string representation. */
  static const char * TAG_FAMILY;
  /** Fantasy string representation. */
  static const char * TAG_FANTASY;
  /** Film-Noir string representation. */
  static const char * TAG_FNOIR;
  /** Game-Show string representation. */
  static const char * TAG_GSHOW;
  /** History string representation. */
  static const char * TAG_HISTORY;
  /** Horror string representation. */
  static const char * TAG_HORROR;
  /** Music string representation. */
  static const char * TAG_MUSIC;
  /** Musical string representation. */
  static const char * TAG_MUSICAL;
  /** Mystery string representation. */
  static const char * TAG_MYSTERY;
  /** News string representation. */
  static const char * TAG_NEWS;
  /** Reality-TV string representation. */
  static const char * TAG_REALTV;
  /** Romance string representation. */
  static const char * TAG_ROMANCE;
  /** Science-Fiction string representation. */
  static const char * TAG_SCIFI;
  /** Short film string representation. */
  static const char * TAG_SHORT;
  /** Sport string representation. */
  static const char * TAG_SPORT;
  /** Talk-show string representation. */
  static const char * TAG_TSHOW;
  /** Thriller string representation. */
  static const char * TAG_THRILL;
  /** War film string representation. */
  static const char * TAG_WAR;
  /** Western string representation. */
  static const char * TAG_WESTERN;
  /** Unknown genres string representation. */
  static const char * TAG_UNKNOWN;
  /** i.e: "All" */
  static const char * TAG_ALL;

 /**
  * Constructor that sets the object to ID_UNKNOWN.
  */
  Genres();

  /**
   * Constructor that sets the object from a given 32-bit unsigned int value.
   * @param genres Set of desired genres.
   */
  Genres(const uint32_t genres);

  /**
   * Constructor that sets the object from a given string representation.
   * @param genre String representation of the desired genre.
   */
  Genres(const char * genre);

  /**
   * Assignation operator that sets the object from a given set of genres.
   * @param genres 32-bit unsigned int representing the set of desired genres.
   */
  Genres& operator = (const uint32_t genres);

  /**
   * Comparator that checks if two objects are equal.
   * @param genres The other set of genres.
   */  
  bool operator == (const Genres& genres) const;

  /**
   * Comparator that checks if a Genres object is equal to a 
   * set of genres represented as a 32-bit unsigned integer.
   * @param genres The other set of genres.
   */
  bool operator == (const uint32_t genres) const;
  
  /**
   * Distinct comparator that checks if two objects are
   * distinct.
   * @param genres The other set of genres.
   */
  bool operator != (const Genres& genres) const;

  /**
   * Distinct comparator that checks if a Genres object is different to
   * a set of genres represented as a 32-bit unsigned integer.
   * @param genres The other set of genres.
   */
  bool operator != (const uint32_t genres) const;

  /**
   * Operator that returns the set of genres as a 32-bit unsigned integer.
   */
  operator uint32_t () const;

  /**
   * Operator that returns the string representation of a single set.
   * If the Genres object is representing a set of genres, 
   * then TAG_UNKNOWN or TAG_ALL values are returned.
   */
  operator const char * () const;

  /**
   * Function that performs a bitwise AND operation between two Genres objects.
   * This function is used to compare to Genres objects treating them
   * as a set of genres.
   * @param genres_a A set of genres.
   * @param genres_b Another set of genres.
   * \retval true The two genre sets have a common value.
   * \retval false The two genre sets does not have any common value.
   */
  static bool mask(const Genres& genres_a, const Genres& genres_b);

  /**
   * Friend method used to write the genre string representation 
   * to a ostream object.
   */
  friend std::ostream& operator << (std::ostream& os, const Genres& genre)
  {
    os << (const char *)genre;
    return os;
  }
  
};

#endif
